#ifndef PORTABLE_NUMBER_CONVERSIONS_H_
#define PORTABLE_NUMBER_CONVERSIONS_H_

#include <stdint.h>

#include "src/pbc/portable-primitives.h"

namespace portable {

static inline bool IsMinusZero(double value) {
  return std::bit_cast<int64_t>(value) == std::bit_cast<int64_t>(-0.0);
}

// The fast double-to-(unsigned-)int conversion routine does not guarantee
// rounding towards zero.
// The result is undefined if x is infinite or NaN, or if the rounded
// integer value is outside the range of type int.
static inline int FastD2I(double x) {
  P_DCHECK(x <= INT_MAX);
  P_DCHECK(x >= INT_MIN);
  return static_cast<int32_t>(x);
}

static inline double FastI2D(int x) {
  // There is no rounding involved in converting an integer to a
  // double, so this code should compile to a few instructions without
  // any FPU pipeline stalls.
  return static_cast<double>(x);
}

static bool IsSmiDouble(double value) {
  return value >= Smi::kMinValue && value <= Smi::kMaxValue &&
         !IsMinusZero(value) && value == FastI2D(FastD2I(value));
}

static inline bool DoubleToSmiInteger(double value, int* smi_int_value) {
  if (!IsSmiDouble(value)) return false;
  *smi_int_value = FastD2I(value);
  P_DCHECK(Smi::IsValid(*smi_int_value));
  return true;
}

}  // namespace portable

#endif  // PORTABLE_NUMBER_CONVERSIONS_H_
